﻿using Microsoft.AspNetCore.SignalR;
using Microsoft.Extensions.Logging;
using PmSoft.Web.Abstractions.Notifications;
using PmSoft.Web.Abstractions.RealTime;
using PmSoft.Web.Abstractions.SignalR.Hubs;

namespace PmSoft.Web.Abstractions.SignalR.Notifications;

/// <summary>
/// 使用 SignalR 实现实时通知，向在线用户发送通知。
/// </summary>
public class SignalRRealTimeNotifier : IRealTimeNotifier
{
	/// <summary>
	/// 获取一个值，表示此实时通知器是否仅在被明确请求时使用。
	/// 这里始终返回 false，表示无需特别请求即可使用此通知器。
	/// </summary>
	public bool UseOnlyIfRequestedAsTarget => false;

	/// <summary>
	/// 日志记录器，用于记录通知发送过程中的信息和异常。
	/// </summary>
	private ILogger _logger { get; set; }

	/// <summary>
	/// 在线客户端管理器，用于获取用户的在线客户端。
	/// </summary>
	private readonly IOnlineClientManager _onlineClientManager;

	/// <summary>
	/// SignalR Hub 上下文，用于与客户端通信。
	/// </summary>
	private readonly IHubContext<CommonHub> _hubContext;

	/// <summary>
	/// 初始化 <see cref="SignalRRealTimeNotifier"/> 类的新实例。
	/// </summary>
	/// <param name="logger">日志记录器实例。</param>
	/// <param name="onlineClientManager">在线客户端管理器实例。</param>
	/// <param name="hubContext">SignalR Hub 上下文实例。</param>
	public SignalRRealTimeNotifier(
		ILogger<SignalRRealTimeNotifier> logger,
		IOnlineClientManager onlineClientManager,
		IHubContext<CommonHub> hubContext)
	{
		_onlineClientManager = onlineClientManager;
		_hubContext = hubContext;
		_logger = logger;
	}

	/// <summary>
	/// 异步向指定用户发送实时通知。
	/// 如果用户不在线，则忽略该用户。
	/// </summary>
	/// <param name="userNotifications">要发送的用户通知数组。</param>
	/// <returns>表示异步操作的任务。</returns>
	public async Task SendNotificationsAsync(IUserNotification[] userNotifications)
	{
		foreach (var userNotification in userNotifications)
		{
			try
			{
				var onlineClients = await _onlineClientManager.GetAllByUserIdAsync(userNotification);
				foreach (var onlineClient in onlineClients)
				{
					var signalRClient = _hubContext.Clients.Client(onlineClient.ConnectionId);
					if (signalRClient == null)
					{
						_logger.LogDebug($"无法从 SignalR Hub 获取用户 {userNotification.ToUserIdentifier()} 的连接，连接 ID: {onlineClient.ConnectionId}");
						continue;
					}

					await signalRClient.SendAsync("getNotification", userNotification);
				}
			}
			catch (Exception ex)
			{
				_logger.LogWarning($"无法向用户发送通知，用户标识: {userNotification.ToUserIdentifier()}");
				_logger.LogWarning(ex.ToString(), ex);
			}
		}
	}
}